package com.hopes.bizz.risk.transfer.handler;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.hopes.bizz.common.core.util.CollectionUtils;
import com.hopes.bizz.common.core.util.StringUtils;
import com.hopes.bizz.common.core.validate.ValidatorUtils;
import com.hopes.bizz.risk.transfer.bean.bo.RiskDataBo;
import com.hopes.bizz.risk.transfer.bean.bo.RiskValidate;
import com.hopes.bizz.risk.transfer.bean.dto.RiskBaseDto;
import com.hopes.bizz.risk.transfer.bean.entity.RiskTransferDataEntity;
import com.hopes.bizz.risk.transfer.bean.entity.RiskTransferErrorLogEntity;
import com.hopes.bizz.risk.transfer.bean.entity.RiskTransferLogEntity;
import com.hopes.bizz.risk.transfer.constant.RiskConstant;
import com.hopes.bizz.risk.transfer.constant.RiskErrorType;
import com.hopes.bizz.risk.transfer.service.RiskTransferDataService;
import com.hopes.bizz.risk.transfer.service.RiskTransferErrorLogService;
import com.hopes.bizz.risk.transfer.service.RiskTransferLogService;
import com.hopes.boss.admin.api.resolver.DictResolver;
import com.hopes.boss.admin.api.resolver.enums.AdminDictEnum;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author lyb
 * @version 1.0
 * @date 2024/2/2 13:53
 */
@Slf4j
public abstract class AbstractRiskData<T extends RiskBaseDto> implements RiskDataHandler<T> {
    @Resource
    private RiskTransferErrorLogService transferErrorLogService;
    @Resource
    private RiskTransferLogService riskTransferLogService;

    @Resource
    private RiskTransferDataService riskTransferDataService;

    @Override
    public void handler(RiskDataBo riskDataBo) {
        List<T> dataList = JSON.parseArray(riskDataBo.getData(), getRiskClass());
        // 保存解密数据
        saveDecryptData(riskDataBo.getBatchId(), JSON.toJSONString(dataList));
        // 解析
        for (T t : dataList) {
            parse(t, riskDataBo);
        }
        // 更新日志
        updateLog(riskDataBo, dataList);
    }

    private void parse(T t, RiskDataBo riskDataBo) {
        try {
            // 校验
            RiskValidate validate = validate(t, riskDataBo);
            if (validate.getSuccess()) {
                // 入库
                saveRiskData(t, riskDataBo);
            } else {
                // 保存日志
                saveErrorLog(t, riskDataBo, validate.getMsg());
            }
        } catch (Exception e) {
            log.error("风险数据解析失败:{},{}", e.getMessage(), t.toString());
            saveErrorLog(t, riskDataBo, RiskErrorType.SYSTEM_ERROR);
        }
    }

    protected void saveErrorLog(T t, RiskDataBo riskDataBo, String errorMsg) {
        RiskTransferErrorLogEntity errorLog = new RiskTransferErrorLogEntity();
        errorLog.setBatchId(riskDataBo.getBatchId());
        errorLog.setErrorId(UUID.randomUUID().toString());
        errorLog.setBusId(t.getId());
        errorLog.setOrgId(riskDataBo.getOrgId());
        errorLog.setRequestType(getRequestType().getCode());
        errorLog.setResultTime(LocalDateTime.now());
        errorLog.setReceiveData(JSON.toJSONString(t));
        errorLog.setFailReason(errorMsg);
        errorLog.setCompanyCode(t.getCompanyCode());
        transferErrorLogService.save(errorLog);
    }

    private RiskValidate validate(T t, RiskDataBo riskDataBo) {
        List<String> errorMSg = new ArrayList<>();
        // 校验格式
        for (Class<?> validGroup : RiskConstant.VALIDATE_GROUP_LIST) {
            String content = ValidatorUtils.validateEntity(t, RiskErrorType.DELIMITER, validGroup);
            if (StringUtils.isNotBlank(content)) {
                errorMSg.add(content);
                break;
            }
        }
        // 校验企业编码
        String companyId = DictResolver.getItemValueByLabel(AdminDictEnum.sys_company_code, t.getCompanyCode());
        if (StringUtils.isBlank(companyId) || !StringUtils.equals(riskDataBo.getOrgIdStr(), companyId)) {
            errorMSg.add(RiskErrorType.TOKEN_ERROR);
        }
        return new RiskValidate(errorMSg.stream().filter(StringUtils::isNotBlank).collect(Collectors.joining(RiskErrorType.DELIMITER)));
    }

    private void updateLog(RiskDataBo riskDataBo, List<T> dataList) {
        List<RiskTransferErrorLogEntity> errorList = transferErrorLogService.lambdaQuery()
                .eq(RiskTransferErrorLogEntity::getBatchId, riskDataBo.getBatchId())
                .select(RiskTransferErrorLogEntity::getErrorId)
                .list();
        LambdaUpdateChainWrapper<RiskTransferLogEntity> updateWrapper = riskTransferLogService.lambdaUpdate()
                .eq(RiskTransferLogEntity::getBatchId, riskDataBo.getBatchId())
                .set(RiskTransferLogEntity::getTotalCount, dataList.size());
        if (CollectionUtils.isNotEmpty(errorList)) {
            String errorId = errorList.stream().map(RiskTransferErrorLogEntity::getErrorId).collect(Collectors.joining(","));
            updateWrapper.set(RiskTransferLogEntity::getErrorCount, errorList.size())
                    .set(RiskTransferLogEntity::getStatus, RiskConstant.RISK_TRANSFER_HANDLER_STATUS_COMPLETED_FAILED)
                    .set(RiskTransferLogEntity::getErrorId, errorId);
        } else {
            updateWrapper.set(RiskTransferLogEntity::getStatus, RiskConstant.RISK_TRANSFER_HANDLER_STATUS_COMPLETED_SUCCESSFULLY);
        }
        updateWrapper.update();
    }

    private void saveDecryptData(String batchId, String data) {
        riskTransferDataService.lambdaUpdate()
                .set(RiskTransferDataEntity::getDecryptData, data)
                .eq(RiskTransferDataEntity::getBatchId, batchId)
                .update();
    }

    private Class<T> getRiskClass() {
        ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        return (Class<T>) actualTypeArguments[0];
    }

    protected abstract void saveRiskData(T t, RiskDataBo riskDataBo);
}
